package main;

import java.util.ArrayList;

import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;

public class Main {

	private static String toHexString(byte b){
		return String.format("%02X ", b);
	}
	
	private static void findValidINS(Card card,int initCLA, int endCLA, int initINS,int endINS) {
		ArrayList<String> lista = new ArrayList<String>();
		int p1 = 0x00;
		int p2 = 0x00;
		int ne = 0x01;
		CardChannel channel = card.getBasicChannel();
		for (int cla = initCLA; cla <= endCLA; cla++){
			for (int ins = initINS; ins <= endINS; ins++){
					CommandAPDU commandAPDU = new CommandAPDU(cla, ins, p1, p2, ne);
					try {
						ResponseAPDU apdu = channel.transmit(commandAPDU);
						byte sw1 = (byte) apdu.getSW1();
						
							byte sw2 = (byte) apdu.getSW2();
							String print ="CLA " + toHexString((byte) cla) + "INS "+toHexString((byte) ins)+"Status: "+toHexString(sw1)+toHexString(sw2);

							System.out.println(print );
							if (sw1 != 0x6D){
								System.out.println(print );
								lista.add(print);
							}
					} catch (CardException e) {
						System.out.println("ERROR transmitindo");
						e.printStackTrace();
					}
				}
			}
			System.out.println("Lista de comandos validos:");
			for (String s : lista) {
				System.out.println(s);
			}
	}
	
	private static void findValidP1P2(Card card,int cla, int ins, int initP1,int endP1) {
		ArrayList<String> lista = new ArrayList<String>();
		
		int ne = 0x01;
		CardChannel channel = card.getBasicChannel();
		for (int p1 = initP1; p1 <= endP1; p1++){
			for (int p2 = 0x00; p2 <= 0xFF; p2++){
					CommandAPDU commandAPDU = new CommandAPDU(cla, ins, p1, p2, ne);
					try {
						ResponseAPDU apdu = channel.transmit(commandAPDU);
						byte sw1 = (byte) apdu.getSW1();
							byte sw2 = (byte) apdu.getSW2();
							String print = "P1 "+toHexString((byte) p1)+"P2 "+toHexString((byte) p2)+"Status: "+toHexString(sw1)+toHexString(sw2);

							System.out.println(print );
							if (sw1 != 0x6A){
								System.out.println(print );
								lista.add(print);
							}
					} catch (CardException e) {
						System.out.println("ERROR transmitindo");
						e.printStackTrace();
					}
				}
			}
			System.out.println("Lista de P1P2 validos para CLA " + toHexString((byte) cla) + "INS "
						+ toHexString((byte) ins));
			for (String s : lista) {
				System.out.println(s);
			}
	}
	
	private static void findValidLength(Card card, int cla, int ins, int p1,
			int p2) {
		ArrayList<String> lista = new ArrayList<String>();

		int ne = 0x01;
		CardChannel channel = card.getBasicChannel();
		byte [] data = null;
		ArrayList<Byte> listaData = new ArrayList<Byte>();
		for (int dataIndex = 0; dataIndex < 0xFF; dataIndex++) {
			listaData.add((byte) 0x00);
			data = new byte[listaData.size()];
			for (int i = 0; i< data.length; i++) {
				data[i] = listaData.get(i);
			}
			
			CommandAPDU commandAPDU = new CommandAPDU(cla, ins, p1, p2,data, ne);
			try {
				ResponseAPDU apdu = channel.transmit(commandAPDU);
				byte sw1 = (byte) apdu.getSW1();
				byte sw2 = (byte) apdu.getSW2();
				
				byte[] responseData = apdu.getData(); // Copy
				
				String responseDataStr = "";
				for (byte b : responseData) {
					responseDataStr+=toHexString(b);
				}
				
				String print = "Sent: " + commandAPDU.getNc()+ 
						"Status: " + toHexString(sw1) + toHexString(sw2)
						+"Data: "+responseDataStr;

				System.out.println(print);
				if (sw1 != 0x67) {
					System.out.println(print);
					lista.add(print);
				}
			} catch (CardException e) {
				System.out.println("ERROR transmitindo");
				e.printStackTrace();
			}

		}
		System.out.println("Lista de lonxitudes validas para CLA " + toHexString((byte) cla) + "INS "
						+ toHexString((byte) ins) + "P1 "
						+ toHexString((byte) p1) + "P2 "
						+ toHexString((byte) p2));
		for (String s : lista) {
			System.out.println(s);
		}
	}
	
	public static void main(String[] args) {

		ArrayList<String> lista = new ArrayList<String>();
		TerminalFactory factory = TerminalFactory.getDefault();
		CardTerminals terminals = factory.terminals();
		System.out.println("Esperando conexion");
		boolean connected = false;

		Card _card = null;
		try {
			while (!connected) {

				for (CardTerminal smartCardIOTerminal : terminals
						.list(javax.smartcardio.CardTerminals.State.CARD_PRESENT)) {
					_card = smartCardIOTerminal.connect("*"); 
					System.out.println("Connected to card using protocol: "
							+ _card.getProtocol()+", "+_card.getATR());
					System.out.println("Terminal: "
							+ smartCardIOTerminal.getName());
					connected = true;
				}
			}
			//findValid INS catd, initCLA,endCLA,initINS,endINS
//			findValidINS(_card,0x80,0x80,0x00,0xFF);
			//findValidP1P2 card, CLA,INS,initP1,endP1
//			findValidP1P2(_card,0x80, 0x2E, 0x00, 0x4F);
			//findValidLength card,CLA,INS,P1,P2
			findValidLength(_card, 0x80, 0x58, 0x00, 0x00);
			_card.disconnect(false);
			
		} catch (CardException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}
